package com.lyandwc.lw_bbs.security.config;

import com.lyandwc.lw_bbs.security.common.UserAuthProvider;
import com.lyandwc.lw_bbs.security.common.UserPermEvaluator;
import com.lyandwc.lw_bbs.security.filter.JWTAuthenticationFilter;
import com.lyandwc.lw_bbs.security.handler.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    UserPermEvaluator userPermEvaluator;
    UserAuthProvider userAuthProvider;
    UserNotLoginHandler userNotLoginHandler;
    UserLoginSuccessHandler userLoginSuccessHandler;
    UserLoginFailureHandler userLoginFailureHandler;
    UserAccessDeniedHandler userAccessDeniedHandler;
    UserLogoutSuccessHandler userLogoutSuccessHandler;

    public SecurityConfig(
            UserPermEvaluator userPermEvaluator,
            UserAuthProvider userAuthProvider,
            UserNotLoginHandler userNotLoginHandler,
            UserLoginSuccessHandler userLoginSuccessHandler,
            UserLoginFailureHandler userLoginFailureHandler,
            UserAccessDeniedHandler userAccessDeniedHandler,
            UserLogoutSuccessHandler userLogoutSuccessHandler
    ) {
        this.userPermEvaluator = userPermEvaluator;
        this.userAuthProvider = userAuthProvider;
        this.userNotLoginHandler = userNotLoginHandler;
        this.userLoginSuccessHandler = userLoginSuccessHandler;
        this.userLoginFailureHandler = userLoginFailureHandler;
        this.userAccessDeniedHandler = userAccessDeniedHandler;
        this.userLogoutSuccessHandler = userLogoutSuccessHandler;
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(userPermEvaluator);
        return handler;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(userAuthProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .antMatchers(JWTConfig.whiteListAll).permitAll()
                .antMatchers(HttpMethod.GET, JWTConfig.whiteListGet).permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated()
                .and()
                .httpBasic().authenticationEntryPoint(userNotLoginHandler)
                .and()
                .formLogin().loginProcessingUrl("/login")
                .successHandler(userLoginSuccessHandler)
                .failureHandler(userLoginFailureHandler)
                .and()
                .exceptionHandling().accessDeniedHandler(userAccessDeniedHandler)
                .and()
                .logout().logoutUrl("/logout")
                .logoutSuccessHandler(userLogoutSuccessHandler)
                .and()
                .cors()
                .and()
                .csrf().disable();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.headers().cacheControl();
        http.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), LogoutFilter.class);
    }
}
